package com.bj.barcode;

import java.awt.AWTException;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.util.NoSuchElementException;
import java.util.Random;
import java.util.StringTokenizer;
import java.util.Timer;
import java.util.UUID;

import javax.imageio.ImageIO;

import org.apache.commons.codec.binary.Base64OutputStream;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.BasicResponseHandler;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.apache.http.protocol.HTTP;

import com.google.gson.Gson;


/*
 * 根据配置文件，自动处理验证码上传到服务器
 * 配置文件的字段顺序：
 * 1. xPos, 2.yPos  3.action: moveClick, moveDblClick, screenshot,upload,heartbeat...
 * 2. 异步提交验证码
 * 
 * 
 * */
public class AutoClickBarcode {
   private static final String token=",";
   private static final Log logger = LogFactory.getLog(AutoClickBarcode.class);
   private static Robot robot;
   //private static final Timer timer = new Timer(true);
   private static final String DefualtCode="tttt";
   private static final String uuid=UUID.randomUUID().toString();
   private static String idleImage=null;
   private static final ThreadLocal<String> oldImageLocal = new ThreadLocal<String>();;
   private String localHost="0";
   private String localPort="0";
   public AutoClickBarcode(){
	  try{
		  robot=new Robot();
      }catch (AWTException e) {
		 logger.error(e);
	  }
   }
	protected  void type(Robot robot,String s)
	  {
	    byte[] bytes;
		try {
	 		robot.delay(163);
			bytes = s.getBytes("UTF-8");
		    for (byte b : bytes){
		        int code = b;
		        if (code > 96 && code < 123){
		    	  code = code - 32;
		        }
			    robot.delay(5);
			    robot.keyPress(code);
			    robot.delay(4);
			    robot.keyRelease(code);
		    }//FOR
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
	  }

	/* 鼠标移动，并且20毫秒以后点击对应的坐标 */
	protected void mouseMoveAndClick(Robot robot,int x, int y) {
		robot.mouseMove(x, y);
		robot.delay(145);
		robot.mousePress(KeyEvent.BUTTON1_MASK);
		robot.delay(222);
		robot.mouseRelease(KeyEvent.BUTTON1_MASK);// 松开鼠标左键
	}
	private void mouseMoveAndDoubleClick(Robot robot,int x, int y) {
		robot.mouseMove(x, y);
		robot.delay(145);
		robot.mousePress(KeyEvent.BUTTON1_MASK);
		robot.delay(145);
		robot.mouseRelease(KeyEvent.BUTTON1_MASK);// 松开鼠标左键
		robot.delay(145);
		robot.mousePress(KeyEvent.BUTTON1_MASK);
		robot.delay(145);
		robot.mouseRelease(KeyEvent.BUTTON1_MASK);// 松开鼠标左键
	}
    
	private  RobotPos[] parseConf()
	{
		RobotPos[] pos=new RobotPos[1000];
    	InputStreamReader rd = null;
    	BufferedReader in= null;
    	
    	try {
			 
			File conf = new File(ConstantStri.barCodeConf); 
			String s =""; 
			String xPos="0",yPos="0",width="0",len="0",action="";
			rd = 
				new InputStreamReader(new FileInputStream(conf), "UTF-8");
			in = new BufferedReader(rd);
			int i=0;
			while( (s = in.readLine()) != null) {
				RobotPos rob=new RobotPos();
				if(s.trim().length()<=1){
					break;
				}
				StringTokenizer fenxi=new StringTokenizer(s,token); //空格和逗号做分
				try {
					xPos=fenxi.nextToken().trim();
				} catch (NoSuchElementException e) {
					xPos="0";
					break;
				}
				try {
					yPos=fenxi.nextToken().trim();
				} catch (NoSuchElementException e) {
					yPos="0";
					break;
				}
				try {
					width=fenxi.nextToken().trim();
				} catch (NoSuchElementException e) {
					width="0";
					break;
				}
				try {
					len=fenxi.nextToken().trim();
				} catch (NoSuchElementException e) {
					len="0";
					break;
				}
				try {
					action=fenxi.nextToken();//解析占用标志
				} catch (NoSuchElementException e) {
					break;
				}
				rob.setAction(action);
				rob.setxPos(Integer.parseInt(xPos));
				rob.setyPos(Integer.parseInt(yPos));
				rob.setWidth(Integer.parseInt(width));
				rob.setLength(Integer.parseInt(len));
				logger.info("开始加载保存的weibo链接......");
				if(action==null || action.trim().equals("")
					|| xPos==null || xPos.trim().equals("")){
					break;
				}
				pos[i]=rob;
				i++;
			}//while
		}  catch (FileNotFoundException e) {
			logger.info(e);
		} catch (IOException e) {
			logger.info(e);
		}finally{
			try {
				rd.close();
				in.close();
			} catch (IOException e) {
				logger.info(e);
			}
		}
    	return pos;
	}
	
	private RobotPos action(RobotPos pos){
		try {
			int xPos=pos.getxPos();
			int yPos=pos.getyPos();
			int width=pos.getWidth();
			int length=pos.getLength();
			pos.setUuid(uuid);
			if(pos.getAction().equals("moveClick")){
				logger.info("mouseMoveAndClick "+xPos+"----"+yPos);
				mouseMoveAndClick(robot,xPos,yPos);
			}else if(pos.getAction().equals("moveDblClick")){
			    robot.delay(57);
				mouseMoveAndClick(robot,xPos,yPos);
			}else if(pos.getAction().equals("enter")){
				logger.info("action: enter");
			    robot.delay(157);
				robot.keyPress(KeyEvent.VK_ENTER);
			    robot.delay(111);
				robot.keyRelease(KeyEvent.VK_ENTER);
			    robot.delay(245);
			}else if(pos.getAction().equals("input")){
				logger.info("base64Image typing "+pos.getBarCode());
				if(pos.getBarCode().equals(DefualtCode)){
					return pos;
				}
			    robot.delay(57);
				type(robot,pos.getBarCode());
			}else if(pos.getAction().equals("delay")){
				robot.delay(ConstantStri.beatInvl*xPos);
			}else if(pos.getAction().equals("idleScreen")){//必须配置在screen shot之后！！因为要比较idle图像
				File idle=new File(ConstantStri.idleImageName);
				
				if(idle.exists() && idle.isFile() && idle.getTotalSpace()>100 
						&& idleImage==null){//idle图像文件存在但是没有读取
					logger.info("idleScreen: idle screenshot existed");
					BufferedImage  buff=ImageIO.read(idle);
					ByteArrayOutputStream out = new ByteArrayOutputStream(); 
					ImageIO.write(buff, "PNG", out); 
					byte[] bytes = out.toByteArray(); 
					String base64bytes = Base64.encodeBytes(bytes); 
					String base64Image = "data:image/png;base64," + base64bytes; 
					this.idleImage=base64Image;
				}else if(!idle.exists() || !idle.isFile()
						|| idle.getTotalSpace()<=100){//idle文件生成并且读取没有生成，或者不符合要求
					System.out.println("是否需要截取idle图像?  ");
					System.out.println("请保证验证码没有出现，才能执行以下操作?  ");
	            	System.out.println("输入Y/y表示需要截取图像作为idle图像。  ");
	            	System.out.println("输入N/n表示不截取图像  ");
					String s;
					try   { 
						DataInputStream   in   = 
				            new   DataInputStream( 
				                new   BufferedInputStream(System.in)); 			            
						while((s   =   in.readLine()).length()   !=   0){ 
			               if(s.equalsIgnoreCase("y")){
						        Rectangle screenRect=new Rectangle(xPos,yPos,width,length);
								BufferedImage buff=robot.createScreenCapture(screenRect);
								FileOutputStream out=new FileOutputStream(new File(ConstantStri.idleImageName));
								ImageIO.write(buff, "PNG", out); 
								out.close();
			            	    break;
			               }else if((s.equalsIgnoreCase("n"))){
			            	   break;
			               }else{
			            	   System.out.println("输入Y/y表示需要截取图像作为idle图像。  ");
			            	   System.out.println("输入N/n表示不截取图像  ");
			            	   System.out.println("您的输入无效，请重新输入  ");
			               }
			            } 
			        }   catch(Exception   e)   { 
			            e.printStackTrace(); 
			        } 					
				}
			}else if(pos.getAction().equals("SPACE")){
				robot.keyPress(128);
				robot.delay(ConstantStri.beatInvl);
		    }else if(pos.getAction().equals("screenshotslow")){//直接处理重复图像和idle图像问题，休眠1秒后执行下次扫描！
				//1、截图
				Rectangle screenRect=new Rectangle(xPos,yPos,width,length);
				BufferedImage buff=robot.createScreenCapture(screenRect);
				int w=buff.getWidth();
				int h=buff.getHeight();
				
				//写入图片所在机器的端口!
				BufferedImage img=new BufferedImage(w,h,BufferedImage.TYPE_INT_RGB);//构建画板
				Graphics g=img.getGraphics();//得到画笔
			    g.drawImage(buff,0,0,w,h,null);//把源图片写入画板
			    g.setColor(Color.red);
			    g.setFont(new Font("TimesRoman", Font.BOLD, 10));
			    g.drawString(this.localPort,5,20);  // 添加文字-机器的端口
			    g.dispose();//生成图片				
				ByteArrayOutputStream out = new ByteArrayOutputStream(); 
				ImageIO.write(img, "PNG", out); 
				byte[] bytes = out.toByteArray(); 
				String base64bytes = Base64.encodeBytes(bytes); 
				String base64Image = "data:image/png;base64," + base64bytes; 
				pos.setBase64Image(base64Image);
				out.close();
				
				
				//3.old image处理，比较差异
				String oldImage=(String)oldImageLocal.get();
                //如果是重复图像,仍然继续向服务器发送,因为New图像会冲刷掉以前的图像
				if(base64Image.equals(oldImage) ){
					robot.delay(ConstantStri.beatInvl*5);
					logger.error("duplicated image found!"+System.currentTimeMillis());
				}
				oldImageLocal.set(base64Image);
				logger.info("base64Image=="+xPos+"--"+yPos+"--"+w+"--"+h);
				//通过随机换取像素点判断idle画面,取样10*10=100个像素点
				/**
				int rgb=buff.getRGB(45, 20) & 0xFFFFFF;
				logger.info("RGB of xPos+45, yPos+20=="+rgb);
				boolean idle=true;
				int xr=0,yr=0,tRGB=0;
				for(int x1=1;x1<=10;x1++){
					
					for(int y1=1;y1<=10;y1++){
						Random rm=new Random(System.currentTimeMillis());

						xr=rm.nextInt(w);
						yr=rm.nextInt(h);
						tRGB=buff.getRGB(xr, yr) & 0xFFFFFF;
						//发现了不同RGB值的像素!
						if(tRGB!=rgb){
							logger.info("RGB of "+xr+", "+yr+"=="+tRGB);
							idle=false;
							break;
						}
					}	
					logger.info("RGB of "+xr+", "+yr+"=="+tRGB);
					if(!idle){
						break;
					}else{
						robot.keyPress(128);
						robot.delay(ConstantStri.beatInvl);
					}
				}
                if(idle){
					logger.error("Idle Image found!"+System.currentTimeMillis());
					robot.delay(ConstantStri.beatInvl*5);
					pos.setFlag(false);
					oldImageLocal.set(base64Image);
					return pos;							
                }**/
				logger.info("base64Image is:= "+base64Image);
		    }else if(pos.getAction().equals("upload")){
				//2.上传到服务器
				ClientMsg client=new ClientMsg();
				client.setBase64Image(pos.getBase64Image());
				client.setRequestCommand("sendImage");
				client.setId(uuid);
				pos.setUuid(uuid);
				ClientMsg[] clients=new ClientMsg[1];
				clients[0]=client;
				Gson  json=new Gson();
				String uploadJSon=json.toJson(clients, ClientMsg[].class);
				String rtn=sendJsonToServer(ConstantStri.upLoadURL,uploadJSon,0);
				logger.info("uploaded json is:= "+uploadJSon+"----return:="+rtn);
		    }else if(pos.getAction().equals("heartbeat")){
				//3.启动定时任务，接收服务器的返回值
				   ClientMsg client=new ClientMsg();
				   client.setRequestCommand("verifyCode");
				   String uuid=pos.getUuid();
				   client.setId(uuid);
				   client.setAgent("clickRobot");
				   client.setBase64ImageFlag(1);
				   client.setRemoteIPAddress("0");
				   client.setRemotePort("0");
				   client.setRequestTime(0);
				   client.setResponseTime(0);
				   client.setResponseCommand("0");
				   client.setSubProtocol("0");
				   Gson  json=new Gson();
				   ClientMsg[] clients=new ClientMsg[1];
				   clients[0]=client;
				   String uploadJSon=json.toJson(clients, ClientMsg[].class);
		           logger.info("AutoClickBarcode: heartbeat begin!"+uploadJSon);   
				   int num=0;
		           while(true){
		        	   num++;
		        	   //客户端会循环400次==2分钟，试图从服务器获取输入的验证码，超过则放弃
		        	   //2分钟内如果没有输入验证码，客户端会重新扫描验证码的区域！然后发送新的图像到服务器上去!
		        	   if(num>=ConstantStri.CheckLimit){
		        		   clearCodeFromServer(uuid);
		        		   pos.setBarCode(DefualtCode); 
		        		   pos.setFlag(false);
			   			   robot.keyPress(128);
						   robot.delay(ConstantStri.beatInvl);
		        		   break;
		        	   }
				   		robot.delay(ConstantStri.beatInvl);
				   	    Gson gson=new Gson();
					    String clientMessage=getJsonFromServer(ConstantStri.upLoadURL,uploadJSon);
					  	//logger.info("getJsonFromServer:"+clientMessage);
						String[] params= gson.fromJson(clientMessage, String[].class); 
						if(clientMessage==null || clientMessage.equals("")){
							logger.info("getJsonFromServer: network error!");
							continue;
						}else if(params==null || params.length==0){
							logger.info("getJsonFromServer: parameters are null");
							continue;
						}else if(params[0]==null || params[0].trim().equals("")){// 参考XMLWeibo类！
							continue;
						}else if(params[0].equals("verifyCode")){// 参考XMLWeibo类！
							pos.setBarCode(params[2]);//填充获取到的验证码
							logger.info("AutoClickBarcode: 验证码=="+params[2]);
							break;
						}
		           }//while
		           
		    }//else-if
		} catch (IOException e) {
			logger.error(e);
			pos=null;
		}finally{
			return pos;
		}
		
	}
	
	private void clearCodeFromServer(String uuid){
		   ClientMsg client=new ClientMsg();
		   client.setRequestCommand("clearCode");
		   client.setId(uuid);
		   client.setAgent("clickRobot");
		   client.setBase64ImageFlag(1);
		   client.setRemoteIPAddress("0");
		   client.setRemotePort("0");
		   client.setRequestTime(0);
		   client.setResponseTime(0);
		   client.setResponseCommand("0");
		   client.setSubProtocol("0");
		   Gson  json=new Gson();
		   ClientMsg[] clients=new ClientMsg[1];
		   clients[0]=client;
		   String uploadJSon=json.toJson(clients, ClientMsg[].class);
		   sendJsonToServer(ConstantStri.upLoadURL,uploadJSon,0);
		   logger.info("AutoClickBarcode: clear code!");  
	}
	
	  /** 
     * Sends a JSON string to 不返回JSon
     */ 
    public String sendJsonToServer(String url, String jsonString,int num){ 
        String error="N";//异常标志,如果==Y则需要发起重新连接
        String response = null;
        DefaultHttpClient httpClient= null;
        try {
		    final HttpParams httpParams = new BasicHttpParams(); 
		    HttpConnectionParams.setConnectionTimeout(httpParams, 5000); 
		    HttpConnectionParams.setSoTimeout(httpParams, 5000);
			httpClient = new DefaultHttpClient(httpParams);
			
			HttpPost post = new HttpPost(url); 
			post.setHeader("Content-Type", "application/json"); 
			post.setEntity(new StringEntity(jsonString,"UTF-8")); 

			ResponseHandler<String> responseHandler = new BasicResponseHandler(); 
			response = httpClient.execute(post,responseHandler);
			logger.info(response);
		} catch (UnsupportedEncodingException e) {
			error="Y";
			logger.error(e);
		} catch (ClientProtocolException e) {
			error="Y";
			logger.error(e);
		} catch (IOException e) {
			error="Y";
			logger.error(e);
		}finally{
			httpClient.getConnectionManager().shutdown();
			/*如果出现网络连接异常,一般是ADSL重新拨号引起的,则重新发起连接,前5次每次等待1.5秒，以后每0.6秒发起一次*/
			if(error.equals("Y")){
				if(num<=5 && num>=0){
					robot.delay(ConstantStri.connInvl);
				}else{
					robot.delay(599);
				}
				response=sendJsonToServer(url, jsonString,num++);
			}
		} 
        return response; 
    } 
    /*
     * 接收server返回的JSon
     */
	public static String getJsonFromServer(String url,String jsonString) {
		
		StringBuilder sb = new StringBuilder();
	    DefaultHttpClient httpClient = null;
		try {
		    final HttpParams httpParams = new BasicHttpParams(); 
		    HttpConnectionParams.setConnectionTimeout(httpParams, 5000); 
		    HttpConnectionParams.setSoTimeout(httpParams, 5000);
			httpClient = new DefaultHttpClient(httpParams);
		    // 设置连接超时时间(单位毫秒) 
			HttpPost postRequest = new HttpPost(url);
	 
			postRequest.setHeader("Content-Type", "application/json"); 
			postRequest.setEntity(new StringEntity(jsonString,"UTF-8"));
	 
			HttpResponse response = httpClient.execute(postRequest);
	 
			if (response.getStatusLine().getStatusCode() != 200) {
				throw new RuntimeException("Failed : HTTP error code : "
					+ response.getStatusLine().getStatusCode());
			}
	 
			BufferedReader br = new BufferedReader(
	                        new InputStreamReader((response.getEntity().getContent())));
	 
			String output;
			while ((output = br.readLine()) != null) {
				sb.append(output);
				logger.info(output);
			}
			if(sb.length()<=2){
				return null;
			}
			logger.info("Output from Server .... "+sb.toString()+"\n");
		  
		} catch (Exception e) {
			logger.error(e);
			
		} finally{
			httpClient.getConnectionManager().shutdown();
		}
		return sb.toString();//返回JSon
	}
    public static void main(String[] args) throws Exception {
    	   //通过参数设置传入本地的host和port
   	    AutoClickBarcode click=new AutoClickBarcode();

		if(args[0]!=null){
			click.localHost=args[0];
		}
		if(args[1]!=null){
			click.localPort=args[1];
		}
 		//Timer timer = new java.util.Timer(true);
    	RobotPos[] pos= click.parseConf();
        RobotPos result=new RobotPos();
		try {
            logger.info("Timer Start:"+click.localHost+"---"+click.localPort+"---"+args[0]+"---"+args[1]); 
            pos[0].setUuid(uuid);
            //timer.schedule(new ScanCodeTask(pos[0],localHost,localPort), 0, 5*60*1000);//每隔5分钟扫描一次
    	    //根据配置文件调用,逐步的把uuid,图像base64和打码结果传送下去!
    	    while(true){
    			try {
					robot.delay(ConstantStri.beatInvl);
					pos[0].setUuid(uuid);
					for(int i=0;i<pos.length;i++){
						robot.delay(50);
						if(pos[i]==null){
							break;
						}
						if(!result.isFlag()){
							result.setFlag(true);//发现重复图像和idle图像，需要马上把标志修改回来，不然这个标志一直存在！
							break;
						}
						if(result.getUuid()!=null){
							pos[i].setUuid(result.getUuid());
						}
						if(result.getBase64Image()!=null){
								pos[i].setBase64Image(result.getBase64Image());
						}
						if(result.getBarCode()!=null){
							pos[i].setBarCode(result.getBarCode());
						}
						result=click.action(pos[i]);
					}//for
    			} catch (Exception e) {
    				e.printStackTrace();
    			}finally{
    				result=new RobotPos();
    			}
    	    }//while
		} catch (Exception e) {
			e.printStackTrace();
			//logger.error(e);
		}finally{
			//timer.cancel();
		}
	  
    }
}
